#pragma once
#include <thread>
#include <queue>
#include <mutex>
#include "Log.hpp"
#include <condition_variable>

// 线程池类
class ThreadPool {
public:
    ThreadPool(size_t threads) : stop_(false) {
        for(size_t i = 0;i<threads;++i)
            workers_.emplace_back([this] {
                    for(;;) {
                        std::function<void()> task;
                        {
                            std::unique_lock<std::mutex> lock(this->queue_mutex_);
                            // lambda表达式返回的结果为false时会释放锁并阻塞等待被条件变量唤醒，返回为true继续往下执行
                            this->condition_.wait(lock, [this]{ return this->stop_ || !this->tasks_.empty(); });
                            // 当线程池被关闭时，还需要检查任务队列中是否还有未完成的任务
                            if(this->stop_ && this->tasks_.empty())
                                return;
                            task = std::move(this->tasks_.front());
                            this->tasks_.pop();
                        }
                        // Logger::getInstance().loggger()->debug("start");
                        task();
                        // Logger::getInstance().loggger()->debug("done");
                    }
                }
            );
    }

    template<class F>
    void enqueue(F&& f)
    {
        {
            std::unique_lock<std::mutex> lock(queue_mutex_);
            if(stop_)
                throw std::runtime_error("enqueue on stopped ThreadPool");
            tasks_.emplace(std::forward<F>(f));
        }
        condition_.notify_one();
    }

    ~ThreadPool() {
        {
            std::unique_lock<std::mutex> lock(queue_mutex_);
            stop_ = true;
        }
        condition_.notify_all();
        for(std::thread &worker: workers_)
            worker.join();
    }

private:
    std::vector<std::thread> workers_;
    // 任务队列
    std::queue<std::function<void()>> tasks_;
    std::mutex queue_mutex_;
    std::condition_variable condition_;
    bool stop_;
};